package org.abratuhi.kvngroupware.network;

import java.io.IOException;
import java.io.StringWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;

import org.abratuhi.kvngroupware.server.KVNGroupwareServer;


public class Server implements Runnable{
	
	public final static Integer TIMEOUT = 1000;
	public final static Integer PAUSE = 100;
	
	/**/
	public ServerSocket serverSocket;
	public int server_port;
	
	/**/
	public ArrayList<S_Client> clients = new ArrayList<S_Client>();
	
	/**/
	public KVNGroupwareServer kvnserver;
	
	/**/
	public boolean isUp = false;
	public Thread thread;
	
	/**/
	public Server(KVNGroupwareServer kvnserver, int port){
		this.kvnserver = kvnserver;
		this.server_port = port;
	}
	
	synchronized int getClientsNumber(){
		return clients.size();
	}
	synchronized S_Client getClient(int index){
		return clients.get(index);
	}
	synchronized ArrayList<S_Client> getClients(){
		return this.clients;
	}

	/**/
	public synchronized void up(){
		if(getIsUp() == true) return;
		try {
			if(serverSocket==null) serverSocket = new ServerSocket(server_port);
			setIsUp(true);
			
			System.out.println("Server:\t UP, port="+server_port+".");
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public synchronized void down(){
		//try {
			//serverSocket.close();
			System.out.println("Server:\t DOWN, port="+server_port+".");
		//} catch (IOException e) {
		//	e.printStackTrace();
		//}
	}
	
	/**/
	public void run(){
		System.out.println("Server:\tstarted.");
		while(getIsUp()){
			try {
				/* wait for new connections*/
				Socket s;
				if(serverSocket != null && !serverSocket.isClosed()){
					s = serverSocket.accept();
					//System.out.println("Server:\tnew connection accepted.");
					S_Client tclient = new S_Client(this, s);
					tclient.start();
					clients.add(tclient);
					System.out.println("Server:\tnew client handle added.");
				}
				Thread.sleep(PAUSE);
			} catch (IOException e) {
				e.printStackTrace();
			} catch (InterruptedException e) {
				System.out.println("Server:\tinterrupted.");
				//setRunOK(false);
				break;
			}
		}
		System.out.println("Server:\tstopped.");
	}
	
	public void start(){
		this.setIsUp(true);
		this.thread = new Thread(this);
		this.thread.start();
	}
	
	public void stop(){
		/* stop clients*/
		for(int i=0; i<clients.size(); i++){
			clients.get(i).stop();
		}
		
		/* unset run flag */
		setIsUp(false);
		
		/* interrupt run routine*/
		thread.interrupt();
	}
	
	public void cleanup(){
		ArrayList<S_Client> zombies = new ArrayList<S_Client>();
		for(int i=0; i<getClientsNumber(); i++){
			if(getClient(i).clientSocket.isClosed()) zombies.add(getClient(i));
		}
		clients.removeAll(zombies);
	}
	
	
	/**/
	public synchronized boolean getIsUp(){
		return this.isUp;
	}
	
	public synchronized void setIsUp(boolean run){
		this.isUp = run;
	}
	
	public synchronized void switchIsUp(){
		this.isUp = (this.isUp == true)? false:true;
	}
	
	/**/
	public String getSummary(){
		StringWriter sw = new StringWriter();
		sw.append("**************************************************"+"\n");
		sw.append("*************** SERVER STATISTICS: ***************"+"\n");
		sw.append("**************************************************"+"\n");
		sw.append("Server on port:\t"+server_port+"\n");
		sw.append("Server is up:\t"+String.valueOf(getIsUp())+"\n");
		sw.append("Server's # of clients:\t"+clients.size()+"\n");
		
		return sw.toString();
	}

}
